﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bettzueche.RLLibrary.Types
{
    /// <summary>
    /// A Feature of an RL-state. A state has this Feature or not or partially.
    /// </summary>
    /// <seealso cref="Bettzueche.RLLibrary.Types.Tiling"/>
    public struct Feature : IEquatable<Feature>
    {
        /// <summary>
        /// The identifier of thies <c>Feature</c>.
        /// </summary>
        public int ID;

        /// <summary>
        /// Indicates, wether this Feature ist set.
        /// </summary>
        public bool BinValue;

        //public double DegreeOfSeverity;

        /// <summary>
        /// The fuzzy value, that indicates the degree of markedness. Normaly a value in [0.0, 1.0].
        /// </summary>
        public double FuzzyValue;


        /// <summary>
        /// Initializes a new instance of the <see cref="Feature"/> struct.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <param name="marked">if set to <c>true</c>, this feature is marked / true.</param>
        /// <param name="degree">The degree of markedness. A fuzzy value, normally in the intervall [0.0, 1.0].</param>
        public Feature(int id, bool marked, double degree) {
            ID = id;
            BinValue = marked;
            FuzzyValue = degree;
        }


        #region Operators

        /// <summary>
        /// Performs an implicit conversion from <see cref="Feature"/> to <see cref="System.Int32"/>.
        /// </summary>
        /// <param name="f">The f.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator int(Feature f) {
            return f.ID;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="Feature"/> to <see cref="System.Boolean"/>.
        /// </summary>
        /// <param name="f">The f.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator bool(Feature f) {
            return f.BinValue;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="Feature"/> to <see cref="System.Double"/>.
        /// </summary>
        /// <param name="f">The f.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator double(Feature f) {
            return f.FuzzyValue;
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="f1">The f1.</param>
        /// <param name="f2">The f2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(Feature f1, Feature f2) {
            return f1.Equals(f2);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="f1">The f1.</param>
        /// <param name="f2">The f2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(Feature f1, Feature f2) {
            return !f1.Equals(f2);
        }

        #endregion


        #region Overrides

        public override int GetHashCode() {
            int hash = BinValue ? 17 : 31;
            hash = hash * 19 + ID;
            hash = hash ^ FuzzyValue.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" }, is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if (obj == null)
                return false;
            if (obj is Feature) {
                return this.Equals((Feature)obj);
            }
            return false;
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.
        /// </returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public bool Equals(Feature other) {
            if (other.ID != this.ID)
                return false;
            if (other.FuzzyValue != this.FuzzyValue)
                return false;
            return !(other.BinValue ^ this.BinValue);

        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format("Feature{0}({1}, {2})", ID, BinValue, FuzzyValue);
        }

        #endregion
    }
}
